﻿using System;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Numeric;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Portal.Model;
using Rhino.Mocks;

namespace Portal.Repository.Tests.System
{
	[TestClass()]
	public class ContactInfoRepositoryTests : PortalTests
	{
		#region GetAllBy

		[TestMethod()]
		public void GetAllBy_InfoExists_ReturnsInfo()
		{
			var login = "login";
			var user = Entities.User.Add(
					new User() { Login = login }
				);
			Entities.SaveChanges();

			Entities.ContactInfo.AddRange(
			new ContactInfo[]{
				new ContactInfo(){
					UserId = user.Id,
					Type = ContactInfoType.Email,
					Value ="some e-mail" },
				new ContactInfo(){
					UserId = user.Id,
					Type = ContactInfoType.Phone,
					Value ="some phone" }
			});

			Entities.SaveChanges();

			var repository = GetRepository();
			var result = repository.GetAllBy(login);
			Assert.IsNotNull(result);
			result.Count().Should().Be(2);
		}

		#endregion GetAllBy

		#region DeleteAllBy

		[TestMethod]
		public void DeleteAllBy_UserIsNull_Success()
		{
			var repository = GetRepository();
			repository.DeleteAllBy(null);
		}

		[TestMethod]
		public void DeleteAllBy_UserIsNotNull_Success()
		{
			var user = new User()
			{
				Login = "login"
			};
			Entities.User.Add(user);

			var info1 = new ContactInfo()
			{
				User = user,
				IsDefault = false,
				Value = "initial value 1",
				Type = ContactInfoType.Email,
			};
			Entities.ContactInfo.Add(info1);
			var info2 = new ContactInfo()
			{
				User = user,
				IsDefault = true,
				Value = "initial value 2",
				Type = ContactInfoType.Phone,
			};
			Entities.ContactInfo.Add(info2);
			Entities.SaveChanges();

			var repository = GetRepository();
			repository.DeleteAllBy(user);
			Entities.SaveChanges();

			var result1 = Entities.ContactInfo.Where(i => i.Id == info1.Id).FirstOrDefault();
			result1.Should().BeNull();
			var result2 = Entities.ContactInfo.Where(i => i.Id == info2.Id).FirstOrDefault();
			result2.Should().BeNull();
		}

		#endregion DeleteAllBy

		#region AddOrUpdate

		[TestMethod]
		public void AddOrUpdate_ContactInfoIsNull_ReturnsNull()
		{
			var user = Mocks.DynamicMock<IUser>();
			Mocks.ReplayAll();

			var repository = GetRepository();
			var result = repository.AddOrUpdate(user, null);

			result.Should().BeNull();
		}

		[TestMethod]
		public void AddOrUpdate_CurrentContactInfoIsInserted_ReturnsInfo()
		{
			var user = new User()
			{
				Login = "login"
			};
			Entities.User.Add(user);
			Entities.SaveChanges();

			var info = Mocks.Stub<IContactInfo>();
			info.IsDefault = true;
			info.Value = "value";
			info.Type = ContactInfoType.Email;

			Mocks.ReplayAll();

			var repository = GetRepository();
			var result = repository.AddOrUpdate(user, info);

			result.Should().NotBeNull();
			result.Value.Should().Be("value");
			result.IsDefault.Should().BeTrue();
			result.Type.Should().Be(ContactInfoType.Email);
		}

		[TestMethod]
		public void AddOrUpdate_CurrentContactInfoIsUpdated_ReturnsInfo()
		{
			var user = new User()
			{
				Login = "login"
			};
			Entities.User.Add(user);

			var current = new ContactInfo()
			{
				User = user,
				IsDefault = false,
				Value = "initial value",
				Type = ContactInfoType.Email,
			};
			Entities.ContactInfo.Add(current);

			Entities.SaveChanges();

			var info = Mocks.Stub<IContactInfo>();
			info.IsDefault = true;
			info.Value = "value";
			info.Type = ContactInfoType.Phone;
			SetupResult.For(info.Id).Return(current.Id);

			Mocks.ReplayAll();

			var repository = GetRepository();
			var result = repository.AddOrUpdate(user, info);

			result.Should().NotBeNull();
			result.Value.Should().Be("value");
			result.IsDefault.Should().BeTrue();
			result.Type.Should().Be(ContactInfoType.Phone);
		}

		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void AddOrUpdate_UserIsNull_ThrowsException()
		{
			var info = Mocks.DynamicMock<IContactInfo>();
			Mocks.ReplayAll();

			var repository = GetRepository();
			var result = repository.AddOrUpdate(null, info);
		}
		#endregion AddOrUpdate

		private ContactInfoRepository GetRepository()
		{
			return new ContactInfoRepository(Entities);
		}
	}
}